local newt = reload("newt")
local delt = reload("delt")
local delts = reload("delts")
local class = reload("class")
local super = reload("super.basic")

---@class database : super.basic @sqldatabase 基类
local this = class(super)

function this:ctor()
    super.ctor(self)
    self._cook = 0
    self._watch = {}
    self:closure()
end

function this:launch()
    super.launch(self)
end

---生成凭证
function this:cook()
    local cook = self._cook
    cook = cook + 1
    self._cook = cook
    return cook
end

---句柄函数
function this:hand()
    return function (hand)
        self._hand = hand
        return self
    end
end

function this:auth()
    local hand = self._hand
    hand.auth()
end

---监听函数
function this:watch(ireply, ...)
    ---记录转换类型-稍后使用
    self._ireply = ireply
    ---记录调用参数-稍后使用
    local vlen = select("#", ...)
    if vlen > 0 then
        local args = newt()
        for i = 1, vlen do
            local v = select(i, ...)
            table.insert(args, v)
        end
        self._fargs = args
    end
    return self._closure
end

---生成闭包函数
function this:closure()
    local watch = self._watch
    self._closure = function (callback, ...)
        ---保存监听信息
        local info = newt()
        watch[self._cook] = info

        ---记录回调函数
        info.f = callback
        info.ireply = self._ireply
        ---保存携带参数(用于避免不断产生闭包的情况)
        local vlen = select("#", ...)
        local args = newt()
        info.args = args

        ---可能需要附带参数
        info.fargs = self._fargs
        self._fargs = nil

        for i = 1, vlen do
            local arg = select(i, ...)
            table.insert(args, arg)
        end

        ---标记需要回调
        self:callback(self._cook)
    end
end

function this:reply(cook, ...)
    local info = self._watch[cook]
    self._watch[cook] = nil
    if info then
        local ireply = info.ireply
        self:decode(ireply, info, ...)
        ---追加返回参数
        delts(info.f(table.unpack(info.args)))
        ---回收数据
        delt(info.args)
        delt(info)
        return
    end
    local hand = self._hand
    hand.reply(...)
end

function this:nonepush(args, ...)
    local len = select("#", ...)
    for i = 1, len do
        local v = select(i, ...)
        table.insert(args, v)
    end
end

function this:selectpush(args, fields, rows)
    if fields and rows then
        local col = #fields
        for _, row in ipairs(rows) do
            for i = 1, col do
                local key = fields[i]
                local val = row[i]
                row[i] = nil
                row[key] = val
            end
        end
        table.insert(args, rows)
        delt(fields)
    else
        table.insert(args, newt())
    end
end

function this:selectMapPush(args, fields, rows)
    if fields and rows then
        local col = #fields
        local map = newt()
        for _, row in ipairs(rows) do
            map[row[1]] = row[2]
        end
        table.insert(args, rows)
        delt(fields)
        delts(rows)
    else
        table.insert(args, newt())
    end
end

---table 列表
function this:showTablesPush(args, fields, rows)
    if fields and rows then
        for i, row in ipairs(rows) do
            rows[i] = row[1]
            delt(row)
        end
        table.insert(args, rows)
        delt(fields)
    else
        table.insert(args, newt())
    end
end

---table 创建sql
function this:showCreateTablePush(args, fields, rows)
    if fields and rows then
        --删除影响项
        local str = rows[1][2]
        str = string.gsub(str, " AUTO_INCREMENT=%d*", "")
        str = string.gsub(str, " USING BTREE", "")
        str = string.gsub(str, " ROW_FORMAT=DYNAMIC", "")
        str = string.gsub(str, " ROW_FORMAT=FIXED", "")
        str = string.gsub(str, " ROW_FORMAT=COMPACT", "")
        str = string.gsub(str, "ENGINE=InnoDB", "ENGINE=InnoDB")
        table.insert(args, rows[1][2])
        delt(fields)
        delts(rows)
    end
end

---table 字段信息
function this:showTableColumnPush(args, fields, rows)
    if fields and rows then
        local col = #fields
        local map = newt()
        for _, row in ipairs(rows) do
            for i = 1, col do
                local key = fields[i]
                local val = row[i]
                row[i] = nil
                row[key] = val
            end
            map[row.Field] = row
            row.Key = nil        ---有数据的时候会变化
            row.Privileges = nil ---权限信息不需要
        end

        table.insert(args, map)
        delt(fields)
        delt(rows)
    else
        table.insert(args, newt())
    end
end

---table 索引信息
function this:showTableIndexPush(args, fields, rows)
    if fields and rows then
        local col = #fields
        local map = newt()
        for _, row in ipairs(rows) do
            for i = 1, col do
                local key = fields[i]
                local val = row[i]
                row[i] = nil
                row[key] = val
            end
            row.Cardinality = nil ---去掉基数信息
            row.Sub_part = nil ---去掉基数信息

            local info = map[row.Key_name]
            if not info then
                local Column_name = newt()
                table.insert(Column_name, row.Column_name)
                row.Column_name = Column_name
                map[row.Key_name] = row
            else
                table.insert(info.Column_name, row.Column_name)
            end
        end

        table.insert(args, map)
        delt(fields)
        delt(rows)
    else
        table.insert(args, newt())
    end
end

function this:showProcedureListPush(args, fields, rows)
    if fields and rows then
        local col = #fields
        local list = newt()
        for _, row in ipairs(rows) do
            table.insert(list, row[2])
        end
        table.insert(args, list)
        delt(fields)
        delts(rows)
    else
        table.insert(args, newt())
    end
end

function this:showCreateProcedurePush(args, fields, rows)
    if fields and rows then
        local str = rows[1][5]
        local sql = str:gsub("CREATE%s+DEFINER=`[^`]+`@`[^`]+`%s+", "CREATE ")
        table.insert(args, sql)
        delt(fields)
        delts(rows)
    end
end

return this
